/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.service.knowledge;

import cn.ac.nercis.pes.common.constant.knowledge.IndustryType;
import cn.ac.nercis.pes.common.constant.knowledge.TargetLevel;
import cn.ac.nercis.pes.model.dto.common.Result;
import cn.ac.nercis.pes.model.dto.common.ResultCode;
import cn.ac.nercis.pes.model.dto.knowledge.KmRiskDescDTO;
import cn.ac.nercis.pes.repository.dal.knowledge.KmRiskDescRepository;
import cn.ac.nercis.pes.repository.dal.knowledge.KmTargetRepository;
import cn.ac.nercis.pes.repository.mapper.knowledge.KmCommonMapper;
import cn.ac.nercis.pes.repository.model.knowledge.KmRiskDescDO;
import cn.ac.nercis.pes.repository.model.knowledge.KmTargetDO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 风险描述信息（知识库）服务
 *
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public record KmRiskDescService(KmRiskDescRepository kmRiskDescRepository,
                                KmTargetRepository kmTargetRepository) {
    @Autowired
    public KmRiskDescService {
    }

    public List<KmRiskDescDTO> findKmRiskDesc(String layerTargetName, TargetLevel level){
        var targets = this.kmTargetRepository.findAllByLevel(level);
        var layerTarget = targets.stream().filter(kt -> StringUtils.equals(kt.getName(), layerTargetName))
                .findFirst()
                .orElse(null);
        if (Objects.isNull(layerTarget)) {
            return Collections.emptyList();
        }
        return targets.stream()
                .filter(ut -> StringUtils.equals(ut.getParentId(), layerTarget.getId()))
                .sorted(Comparator.comparingInt(KmTargetDO::getSort))
                .flatMap(ut -> findKmRiskDesc(ut.getId(), targets).stream())
                .toList();
    }

    public List<KmRiskDescDTO> findKmRiskDesc(String unitTargetId){
        return this.kmRiskDescRepository.findAllByUnitTargetId(unitTargetId)
                .stream()
                .sorted(Comparator.comparingInt(KmRiskDescDO::getSort))
                .map(KmCommonMapper.INSTANCE::toDTO)
                .toList();
    }

    public Result<String> saveKmRiskDesc(KmRiskDescDTO kmRiskDesc) {
        try {
            if (StringUtils.isEmpty(kmRiskDesc.getId())) {
                return create(kmRiskDesc);
            } else {
                return modify(kmRiskDesc);
            }
        } catch (Exception e) {
            log.error("保存风险描述信息（知识库）信息出错：", e);
            return Result.failed();
        }
    }

    public Result<String> batchKmRiskDesc(List<KmRiskDescDTO> data) {
        Result<String> result = Result.success();
        for (var item : data) {
            result = saveKmRiskDesc(item);
            if (!result.isSuccess()) {
                break;
            }
        }
        return result;
    }

    public Result<String> deleteKmRiskDesc(String id) {
        try {
            return this.kmRiskDescRepository.findById(id)
                    .map(entity -> {
                        kmRiskDescRepository.delete(entity);
                        return entity;
                    })
                    .map(KmRiskDescDO::getId)
                    .map(Result::success)
                    .orElse(Result.failed());
        } catch (Exception ex) {
            log.error("删除知识库风险描述信息出错：", ex);
            return Result.failed();
        }
    }

    public Result<String> batchDeleteKmRiskDesc(Set<String> ids) {
        Result<String> result = Result.success();
        for (String id : ids) {
            result = deleteKmRiskDesc(id);
            if (!result.isSuccess()) {
                break;
            }
        }
        return result;
    }

    private Result<String> create(KmRiskDescDTO kmRiskDesc) {
        var unitTarget = this.kmTargetRepository.findById(kmRiskDesc.getUnitTargetId()).orElse(null);
        if (Objects.isNull(unitTarget)) {
            return Result.failed("未获取到指定测评指标信息！");
        }
        var lastSort = this.kmRiskDescRepository.findAllByUnitTargetId(kmRiskDesc.getUnitTargetId())
                .stream()
                .mapToInt(KmRiskDescDO::getSort)
                .max()
                .orElse(0);
        return Optional.of(KmCommonMapper.INSTANCE.toDO(kmRiskDesc))
                .map(e -> {
                    e.setIndustry(IndustryType.DEFAULT);
                    e.setLayerTargetId(unitTarget.getParentId());
                    e.setLevel(unitTarget.getLevel());
                    e.setSort(lastSort + 1);
                    e.setCreateTime(LocalDateTime.now());
                    return e;
                })
                .map(kmRiskDescRepository::save)
                .map(entity-> Result.success(entity.getId()))
                .orElse(Result.failed());
    }

    private Result<String> modify(KmRiskDescDTO kmRiskDesc) {
        var source = this.kmRiskDescRepository.findById(kmRiskDesc.getId()).orElse(null);
        if (Objects.isNull(source)) {
            return Result.failed(ResultCode.NOT_FOUND);
        }
        if (!StringUtils.equals(source.getUnitTargetId(), kmRiskDesc.getUnitTargetId())) {
            var unitTarget = this.kmTargetRepository.findById(kmRiskDesc.getUnitTargetId()).orElse(null);
            if (Objects.isNull(unitTarget)) {
                return Result.failed("未获取到指定测评指标信息！");
            }
            var lastSort = this.kmRiskDescRepository.findAllByUnitTargetId(kmRiskDesc.getUnitTargetId())
                    .stream()
                    .mapToInt(KmRiskDescDO::getSort)
                    .max()
                    .orElse(0);
            source.setLayerTargetId(unitTarget.getParentId());
            source.setUnitTargetId(kmRiskDesc.getUnitTargetId());
            source.setSort(lastSort + 1);
            source.setLevel(unitTarget.getLevel());
        }
        source.setDesc(kmRiskDesc.getDesc());
        source.setModifyTime(LocalDateTime.now());
        return Optional.of(kmRiskDescRepository.save(source))
                .map(entity-> Result.success(entity.getId()))
                .orElse(Result.failed(ResultCode.FAIL));
    }

    private List<KmRiskDescDTO> findKmRiskDesc(String unitTargetId, List<KmTargetDO> targets) {
        return kmRiskDescRepository.findAllByUnitTargetId(unitTargetId)
                .stream()
                .sorted(Comparator.comparingInt(KmRiskDescDO::getSort))
                .map(entity->{
                    var dto =  KmCommonMapper.INSTANCE.toDTO(entity);
                    dto.setUnitTargetName(getTargetName(targets, entity.getUnitTargetId()));
                    return dto;
                })
                .toList();
    }

    private String getTargetName(List<KmTargetDO> targets, String unitTargetId){
        return targets.stream()
                .filter(ra->StringUtils.equals(ra.getId(),unitTargetId))
                .map(KmTargetDO::getName)
                .findFirst()
                .orElse(StringUtils.EMPTY);
    }

}